/***************************************************
 ** @Desc : This file for 商户实现方法
 ** @Time : 2019.04.13 10:37
 ** @Author : Joker
 ** @File : merchant_impl
 ** @Last Modified by : Joker
 ** @Last Modified time: 2019.04.13 10:37
 ** @Software: GoLand
****************************************************/
package implement

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"recharge/models"
	"recharge/sys"
	"recharge/utils"
	"recharge/utils/interface_config"
	"regexp"
	"strings"
)

type MerchantImpl struct{}

var globalMethod = utils.GlobalMethod{}
var encrypt = utils.Encrypt{}
var merchantMdl = models.Merchant{}
var AES = utils.AES{}

// 更新商户金额
func (the *MerchantImpl) UpdateMerchantAmount(merchant models.Merchant, msg string, flag int) (string, int) {
	encode := encrypt.EncodeMd5([]byte(globalMethod.RandomString(32)))
	result, err := the.XFQueryBalanceV2(merchant, encode)
	if err != nil {
		return err.Error(), flag
	}

	resp := models.XFQueryResponseBody{}
	err = json.Unmarshal(result, &resp)
	if err != nil {
		sys.LogError("response data format is error:", err)
		return "先锋余额查询响应数据格式错误", flag
	}

	if strings.Compare("00000", resp.ResCode) != 0 {
		return "先锋余额查询错误：" + resp.ResMessage, flag
	}

	merchant.TotalAmount, _ = globalMethod.MoneyFenToYuan(resp.Balance)
	merchant.FrozenAmount, _ = globalMethod.MoneyFenToYuan(resp.FreezeAmount)
	merchant.UsableAmount, _ = globalMethod.MoneyFenToYuan(resp.Available)
	merchant.EditTime = globalMethod.GetNowTime()

	flag = merchantMdl.UpdateMerchant(merchant)

	return msg, flag
}

// 构造余额查询请求
func (the *MerchantImpl) XFQueryBalance(mt models.Merchant) (result []byte, err error) {
	//请求参数
	reqParams := url.Values{}
	reqParams.Add("service", "REQ_QUERY_BALANCE")
	reqParams.Add("secId", interface_config.SECID)
	reqParams.Add("version", interface_config.VERSION)
	reqParams.Add("reqSn", globalMethod.GetNowTimeV2()+globalMethod.RandomString(10))
	reqParams.Add("merchantId", mt.MerchantNo)

	//生成签名
	params := reqParams.Encode()
	signBytes, err := the.XFGenerateSign(params, mt.SecretKey)
	if err != nil {
		msg := "先锋余额查询生成签名失败"
		sys.LogTrace(msg, err)
		return nil, errors.New(msg)
	}
	reqParams.Add("sign", string(signBytes))

	// 发送请求
	resp, err := http.PostForm(interface_config.XF_QUERY_URL, reqParams)
	if err != nil {
		s := "先锋余额查询请求失败"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}

	// 处理响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		s := "先锋余额查询响应为空"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}
	defer resp.Body.Close()

	bytes, err := AES.AesDecrypt(body, []byte(mt.SecretKey))
	if err != nil {
		s := "先锋余额查询响应解密错误"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}

	return bytes, err
}

// 构造余额查询请求 v5.0.0版本
func (the *MerchantImpl) XFQueryBalanceV2(mt models.Merchant, b string) (result []byte, err error) {
	//请求参数
	reqParams := url.Values{}
	reqParams.Add("service", "REQ_QUERY_BALANCE")
	reqParams.Add("version", interface_config.VERSION_V2)
	reqParams.Add("merchantId", mt.MerchantNo)

	blockKey, err := the.XFHandleBlockKey(b, mt.SecretKey)
	if err != nil {
		s := "先锋余额查询aes秘钥加密失败"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}
	reqParams.Add("tm", blockKey)

	// 需要的加密参数
	dataParams := models.XFBalanceQueryData{}
	dataParams.MerchantId = mt.MerchantNo

	// 加密参数
	dataString, _ := json.Marshal(&dataParams)
	data, err := AES.AesEncryptV2(string(dataString), b)
	if err != nil {
		return nil, err
	}
	reqParams.Add("data", data)

	// 生成签名
	respParams := map[string]string{}
	respParams["service"] = "REQ_QUERY_BALANCE"
	respParams["version"] = interface_config.VERSION_V2
	respParams["merchantId"] = mt.MerchantNo
	respParams["data"] = data
	respParams["tm"] = blockKey
	params := globalMethod.ToStringByMap(respParams)

	signBytes, err := the.XFGenerateSignV2(params, interface_config.PRIVATE_KEY)
	if err != nil {
		msg := "先锋余额查询生成签名失败"
		sys.LogTrace(msg, err)
		return nil, errors.New(msg)
	}
	reqParams.Add("sign", string(signBytes))

	// 发送请求
	resp, err := http.PostForm(interface_config.XF_QUERY_URL, reqParams)
	if err != nil {
		s := "先锋余额查询请求失败"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}

	// 处理响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		s := "先锋余额查询响应为空"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}
	defer resp.Body.Close()

	respData := models.RespData{}
	err = json.Unmarshal(body, &respData)
	if err != nil {
		s := "先锋余额查询响应数据格式错误"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}

	if respData.Data == "" {
		sys.LogInfo("先锋余额查询响应：", string(body))
		return nil, errors.New("先锋余额查询响应data为空！")
	}

	s, err := the.DecryptRespDataByPrivateKey(respData.Tm)
	bytes, err := AES.AesDecryptV2([]byte(respData.Data), s)
	if err != nil {
		s := "先锋余额查询响应解密错误"
		sys.LogTrace(s, err)
		return nil, errors.New(s)
	}

	return bytes, err
}

// 先锋查询生成签名
func (*MerchantImpl) XFGenerateSign(params, key string) (string, error) {
	paramsMd5 := encrypt.EncodeMd5([]byte(params))
	encrypto, err := encrypt.RsaEncrypto([]byte(strings.ToLower(paramsMd5)), []byte(utils.STARTKEY+key+utils.ENDKEY))
	if err != nil {
		return "", err
	}

	base64Encode := encrypt.Base64Encode(encrypto)
	return base64Encode, nil
}

// 先锋查询生成签名  5.0.0版本
func (*MerchantImpl) XFGenerateSignV2(params, key string) (string, error) {
	encrypto, err := encrypt.SHA256WithRSAToSign([]byte(params), []byte(key))
	if err != nil {
		return "", err
	}

	base64Encode := encrypt.Base64Encode(encrypto)
	return base64Encode, nil
}

// 对秘钥进行rsa公钥加密
func (*MerchantImpl) XFHandleBlockKey(b, k string) (string, error) {
	encrypto, err := encrypt.RsaEncrypto([]byte(b), []byte(utils.STARTKEY+string(k)+utils.ENDKEY))
	if err != nil {
		return "", err
	}

	base64Encode := encrypt.Base64Encode(encrypto)
	return base64Encode, nil
}

// 对响应进行aes私钥解密
func (*MerchantImpl) DecryptRespDataByPrivateKey(tm string) ([]byte, error) {
	tmb, err := encrypt.Base64Decode(tm)
	if err != nil {
		return nil, err
	}

	b, err := encrypt.RsaDecrypto(tmb, []byte(interface_config.PRIVATE_KEY))
	if err != nil {
		return nil, err
	}
	return b, nil
}

/* *
 * @Description: 验证用户信息
 * @Author: Joker
 * @Date: 2019.04.08 9:27
 * @Param: pwd: 旧密码 newPwd: 新密码
 * @return: string: 错误原因 bool: 验证是否通过
 **/
func (*MerchantImpl) VerificationUserInfo(pwd, newPwd string) (string, bool) {
	if pwd == "" || newPwd == "" {
		return "密码不能为空！", false
	}

	matched, _ := regexp.MatchString(`^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){5,19}$`, newPwd)
	if !matched {
		return "密码只能输入6-20个以字母开头、可带数字、“_”、“.”的字串!", false
	}

	return "", true
}
